/*
SRMM

Copyright 2000-2005 Miranda ICQ/IM project,
Copyright 2006-2009 Joe Kucera
all portions of this codebase are copyrighted to the people 
listed in contributors.txt.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/
#include "commonheaders.h"
#pragma hdrstop

#include "m_fontservice.h"

extern HINSTANCE g_hInst;

#define FONTF_BOLD   1
#define FONTF_ITALIC 2
struct FontOptionsList
{
  TCHAR*   szDescr;
  COLORREF defColour;
  TCHAR*   szDefFace;
  BYTE     defStyle;
  char     defSize;
}
static fontOptionsList[] = {
  { LPGENT("Outgoing messages"), RGB(0, 0, 0),     _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Outgoing URLs"),     RGB(0, 0, 255),   _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Outgoing files"),    RGB(0, 0, 0),     _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Incoming messages"), RGB(0, 0, 0),     _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Incoming URLs"),     RGB(0, 0, 255),   _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Incoming files"),    RGB(0, 0, 0),     _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Outgoing name"),     RGB(50, 56, 114), _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Outgoing time"),     RGB(0, 0, 0),     _T("Terminal"), FONTF_BOLD, -9},
  { LPGENT("Outgoing colon"),    RGB(50, 56, 114), _T("Arial"),    0,          -11},
  { LPGENT("Incoming name"),     RGB(215, 0, 0),   _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Incoming time"),     RGB(0, 0, 0),     _T("Terminal"), FONTF_BOLD, -9},
  { LPGENT("Incoming colon"),    RGB(215, 0, 0),   _T("Arial"),    0,          -11},
  { LPGENT("Message area"),      RGB(0, 0, 0),     _T("Arial"),    FONTF_BOLD, -12},
  { LPGENT("Notifications"),     RGB(90, 90, 160), _T("Arial"),    0,          -12},  
};

const int msgDlgFontCount = SIZEOF(fontOptionsList);

#if defined( _UNICODE )
static BYTE MsgDlgGetFontDefaultCharset(const TCHAR* szFont)
{
  return DEFAULT_CHARSET;
}
#else
// get font charset according to current CP
static BYTE MsgDlgGetCPDefaultCharset()
{
	switch (GetACP()) {
		case 1250:
			return EASTEUROPE_CHARSET;
		case 1251:
			return RUSSIAN_CHARSET;
		case 1252:
			return ANSI_CHARSET;
		case 1253:
			return GREEK_CHARSET;
		case 1254:
			return TURKISH_CHARSET;
		case 1255:
			return HEBREW_CHARSET;
		case 1256:
			return ARABIC_CHARSET;
		case 1257:
			return BALTIC_CHARSET;
		case 1361:
			return JOHAB_CHARSET;
		case 874:
			return THAI_CHARSET;
		case 932:
			return SHIFTJIS_CHARSET;
		case 936:
			return GB2312_CHARSET;
		case 949:
			return HANGEUL_CHARSET;
		case 950:
			return CHINESEBIG5_CHARSET;
		default:
			return DEFAULT_CHARSET;
	}
}

static int CALLBACK EnumFontFamExProc(const LOGFONT *lpelfe, const TEXTMETRIC *lpntme, DWORD FontType, LPARAM lParam)
{
	*(int*)lParam = 1;
	return 0;
}

// get font charset according to current CP, if available for specified font
static BYTE MsgDlgGetFontDefaultCharset(const TCHAR* szFont)
{
	HDC hdc;
	LOGFONT lf = {0};
	int found = 0;

	_tcscpy(lf.lfFaceName, szFont);
	lf.lfCharSet = MsgDlgGetCPDefaultCharset();

	// check if the font supports specified charset
	hdc = GetDC(0);
	EnumFontFamiliesEx(hdc, &lf, &EnumFontFamExProc, (LPARAM)&found, 0);
	ReleaseDC(0, hdc);

	if (found)
		return lf.lfCharSet;
	else // no, give default
		return DEFAULT_CHARSET;
}
#endif

void LoadMsgDlgFont(int i, LOGFONT* lf, COLORREF * colour)
{
  char str[32];
  int style;
  DBVARIANT dbv;

  if (colour) {
    wsprintfA(str, "Font%dCol", i);
    *colour = SRMMGetSettingDword(str, fontOptionsList[i].defColour);
  }
  if ( lf ) {
    wsprintfA(str, "Font%dSize", i);
    lf->lfHeight = (char)SRMMGetSettingByte(str, fontOptionsList[i].defSize);
    lf->lfWidth = 0;
    lf->lfEscapement = 0;
    lf->lfOrientation = 0;
    wsprintfA(str, "Font%dSty", i);
    style = SRMMGetSettingByte(str, fontOptionsList[i].defStyle);
    lf->lfWeight = style & FONTF_BOLD ? FW_BOLD : FW_NORMAL;
    lf->lfItalic = style & FONTF_ITALIC ? 1 : 0;
    lf->lfUnderline = 0;
    lf->lfStrikeOut = 0;
    lf->lfOutPrecision = OUT_DEFAULT_PRECIS;
    lf->lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf->lfQuality = DEFAULT_QUALITY;
    lf->lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    wsprintfA(str, "Font%d", i);
    if (DBGetContactSettingTString(NULL, SRMSGMOD, str, &dbv))
      lstrcpy(lf->lfFaceName, fontOptionsList[i].szDefFace);
    else {
      lstrcpyn(lf->lfFaceName, dbv.ptszVal, SIZEOF(lf->lfFaceName));
      DBFreeVariant(&dbv);
    }
    wsprintfA(str, "Font%dSet", i);
    lf->lfCharSet = SRMMGetSettingByte(str, MsgDlgGetFontDefaultCharset(lf->lfFaceName));
} }

void RegisterSRMMFonts( void )
{
  FontIDT fontid = {0};
  ColourIDT colourid = {0};
  char idstr[10];
  int i, index = 0;

  fontid.cbSize = sizeof(FontID);
  fontid.flags = FIDF_ALLOWREREGISTER | FIDF_DEFAULTVALID;
  for ( i = 0; i < msgDlgFontCount; i++, index++ ) {
    strncpy(fontid.dbSettingsGroup, SRMSGMOD, sizeof(fontid.dbSettingsGroup));
    _tcsncpy(fontid.group, TranslateT("Message Log"), SIZEOF(fontid.group));
    _tcsncpy(fontid.name, TranslateTS(fontOptionsList[i].szDescr), SIZEOF(fontid.name));
    sprintf(idstr, "Font%d", index);
    strncpy(fontid.prefix, idstr, SIZEOF(fontid.prefix));
    fontid.order = index;

    fontid.deffontsettings.colour = fontOptionsList[i].defColour;
    fontid.deffontsettings.size = fontOptionsList[i].defSize;
    fontid.deffontsettings.style = fontOptionsList[i].defStyle;
    _tcsncpy(fontid.deffontsettings.szFace, fontOptionsList[i].szDefFace, SIZEOF(fontid.deffontsettings.szFace));
    fontid.deffontsettings.charset = MsgDlgGetFontDefaultCharset(fontOptionsList[i].szDefFace);
    CallService(MS_FONT_REGISTERT, (WPARAM)&fontid, 0);
  }

  colourid.cbSize = sizeof(ColourID);
  strncpy(colourid.dbSettingsGroup, SRMSGMOD, sizeof(colourid.dbSettingsGroup));
  strncpy(colourid.setting, SRMSGSET_BKGCOLOUR, sizeof(colourid.setting));
  colourid.defcolour = SRMSGDEFSET_BKGCOLOUR;
  _tcsncpy(colourid.name, TranslateT("Background"), SIZEOF(colourid.name));
  _tcsncpy(colourid.group, TranslateT("Message Log"), SIZEOF(colourid.group));
  CallService(MS_COLOUR_REGISTERT, (WPARAM)&colourid, 0);
}

static void LoadDBCheckState(HWND hwndDlg, int idCtrl, const char* szSetting, BYTE bDef)
{
  CheckDlgButton(hwndDlg, idCtrl, SRMMGetSettingByte(szSetting, bDef));
}


static BYTE StoreDBCheckState(HWND hwndDlg, int idCtrl, const char* szSetting)
{
  BYTE bVal = (BYTE)IsDlgButtonChecked(hwndDlg, idCtrl);

  SRMMWriteSettingByte(szSetting, bVal);
  return bVal;
}

/////////////////////////////////////////////////////////////////////////////////////////

struct CheckBoxValues_t
{
  DWORD  style;
  TCHAR* szDescr;
}
static const statusValues[] =
{
  { PF2_ONLINE,     LPGENT("Online")        },
  { PF2_SHORTAWAY,  LPGENT("Away")          },
  { PF2_LONGAWAY,   LPGENT("NA")            },
  { PF2_LIGHTDND,   LPGENT("Occupied")      },
  { PF2_HEAVYDND,   LPGENT("DND")           },
  { PF2_FREECHAT,   LPGENT("Free for chat") },
  { PF2_INVISIBLE,  LPGENT("Invisible")     },
  { PF2_OUTTOLUNCH, LPGENT("Out to lunch")  },
  { PF2_ONTHEPHONE, LPGENT("On the phone")  }
};

static void FillCheckBoxTree(HWND hwndTree, const struct CheckBoxValues_t *values, int nValues, DWORD style)
{
  TVINSERTSTRUCT tvis;
  int i;

  tvis.hParent = NULL;
  tvis.hInsertAfter = TVI_LAST;
  tvis.item.mask = TVIF_PARAM | TVIF_TEXT | TVIF_STATE;
  for (i = 0; i < nValues; i++) {
    tvis.item.lParam = values[i].style;
    tvis.item.pszText = TranslateTS(values[i].szDescr);
    tvis.item.stateMask = TVIS_STATEIMAGEMASK;
    tvis.item.state = INDEXTOSTATEIMAGEMASK((style & tvis.item.lParam) != 0 ? 2 : 1);
    TreeView_InsertItem( hwndTree, &tvis );
}	}

static DWORD MakeCheckBoxTreeFlags(HWND hwndTree)
{
  DWORD flags = 0;
  TVITEM tvi;

  tvi.mask = TVIF_HANDLE | TVIF_PARAM | TVIF_STATE;
  tvi.hItem = TreeView_GetRoot(hwndTree);
  while (tvi.hItem) {
    TreeView_GetItem(hwndTree, &tvi);
    if (((tvi.state & TVIS_STATEIMAGEMASK) >> 12 == 2))
      flags |= tvi.lParam;
    tvi.hItem = TreeView_GetNextSibling(hwndTree, tvi.hItem);
  }
  return flags;
}

static INT_PTR CALLBACK DlgProcOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg) {
    case WM_INITDIALOG:
      {
        DWORD msgTimeout, avatarHeight;

        TranslateDialogDefault(hwndDlg);
        SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_POPLIST), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_POPLIST), GWL_STYLE) | TVS_NOHSCROLL | TVS_CHECKBOXES);
        FillCheckBoxTree(GetDlgItem(hwndDlg, IDC_POPLIST), statusValues, SIZEOF(statusValues),
          SRMMGetSettingDword(SRMSGSET_POPFLAGS, SRMSGDEFSET_POPFLAGS));
        CheckDlgButton(hwndDlg, IDC_SHOWBUTTONLINE, g_dat->flags&SMF_SHOWBTNS);
        CheckDlgButton(hwndDlg, IDC_SHOWINFOLINE, g_dat->flags&SMF_SHOWINFO);
        LoadDBCheckState(hwndDlg, IDC_AUTOMIN,        SRMSGSET_AUTOMIN,        SRMSGDEFSET_AUTOMIN);
        LoadDBCheckState(hwndDlg, IDC_AUTOCLOSE,      SRMSGSET_AUTOCLOSE,      SRMSGDEFSET_AUTOCLOSE);
        LoadDBCheckState(hwndDlg, IDC_SAVEPERCONTACT, SRMSGSET_SAVEPERCONTACT, SRMSGDEFSET_SAVEPERCONTACT);
        LoadDBCheckState(hwndDlg, IDC_CASCADE,        SRMSGSET_CASCADE,        SRMSGDEFSET_CASCADE);
        LoadDBCheckState(hwndDlg, IDC_SENDONENTER,    SRMSGSET_SENDONENTER,    SRMSGDEFSET_SENDONENTER);
        LoadDBCheckState(hwndDlg, IDC_SENDONDBLENTER, SRMSGSET_SENDONDBLENTER, SRMSGDEFSET_SENDONDBLENTER);
        LoadDBCheckState(hwndDlg, IDC_STATUSWIN,      SRMSGSET_STATUSICON,     SRMSGDEFSET_STATUSICON);

        CheckDlgButton(hwndDlg, IDC_AVATARSUPPORT, g_dat->flags&SMF_AVATAR);
        LoadDBCheckState(hwndDlg, IDC_LIMITAVATARH,   SRMSGSET_LIMITAVHEIGHT,  SRMSGDEFSET_LIMITAVHEIGHT);
        avatarHeight = SRMMGetSettingDword(SRMSGSET_AVHEIGHT, SRMSGDEFSET_AVHEIGHT);
        SetDlgItemInt(hwndDlg, IDC_AVATARHEIGHT, avatarHeight, FALSE);
        EnableWindow(GetDlgItem(hwndDlg, IDC_LIMITAVATARH), IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT));
        if (!IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT))
          EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), FALSE);
        else EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
        CheckDlgButton(hwndDlg, IDC_SHOWSENDBTN, g_dat->flags&SMF_SENDBTN);
        LoadDBCheckState(hwndDlg, IDC_CHARCOUNT,      SRMSGSET_CHARCOUNT,      SRMSGDEFSET_CHARCOUNT);
        LoadDBCheckState(hwndDlg, IDC_AUTOSAVEMSG,    SRMSGSET_AUTOSAVEMSG,    SRMSGDEFSET_AUTOSAVEMSG);
        msgTimeout = SRMMGetSettingDword(SRMSGSET_MSGTIMEOUT, SRMSGDEFSET_MSGTIMEOUT);
        SetDlgItemInt(hwndDlg, IDC_SECONDS, msgTimeout >= SRMSGSET_MSGTIMEOUT_MIN ? msgTimeout / 1000 : SRMSGDEFSET_MSGTIMEOUT / 1000, FALSE);
        EnableWindow(GetDlgItem(hwndDlg, IDC_CASCADE), !IsDlgButtonChecked(hwndDlg, IDC_SAVEPERCONTACT));
        return TRUE;
      }

    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDC_AUTOMIN:
          CheckDlgButton(hwndDlg, IDC_AUTOCLOSE, BST_UNCHECKED);
          break;

        case IDC_AUTOCLOSE:
          CheckDlgButton(hwndDlg, IDC_AUTOMIN, BST_UNCHECKED);
          break;

        case IDC_SENDONENTER:
          CheckDlgButton(hwndDlg, IDC_SENDONDBLENTER, BST_UNCHECKED);
          break;

        case IDC_SENDONDBLENTER:
          CheckDlgButton(hwndDlg, IDC_SENDONENTER, BST_UNCHECKED);
          break;

        case IDC_SAVEPERCONTACT:
          EnableWindow(GetDlgItem(hwndDlg, IDC_CASCADE), !IsDlgButtonChecked(hwndDlg, IDC_SAVEPERCONTACT));
          break;

        case IDC_SECONDS:
          if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
            return 0;
          break;

        case IDC_AVATARSUPPORT:
          EnableWindow(GetDlgItem(hwndDlg, IDC_LIMITAVATARH), IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT));
          if (!IsDlgButtonChecked(hwndDlg, IDC_AVATARSUPPORT))
            EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), FALSE);
          else EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
          break;

        case IDC_LIMITAVATARH:
          EnableWindow(GetDlgItem(hwndDlg, IDC_AVATARHEIGHT), IsDlgButtonChecked(hwndDlg, IDC_LIMITAVATARH));
          break;

        case IDC_AVATARHEIGHT:
          if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
            return 0;
          break;
      }
      SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
      break;
    case WM_NOTIFY:
      switch (((LPNMHDR) lParam)->idFrom) {
        case IDC_POPLIST:
          if (((LPNMHDR) lParam)->code == NM_CLICK) {
            TVHITTESTINFO hti;
            hti.pt.x = (short) LOWORD(GetMessagePos());
            hti.pt.y = (short) HIWORD(GetMessagePos());
            ScreenToClient(((LPNMHDR) lParam)->hwndFrom, &hti.pt);
            if (TreeView_HitTest(((LPNMHDR) lParam)->hwndFrom, &hti))
              if (hti.flags & TVHT_ONITEMSTATEICON) {
                TVITEM tvi;
                tvi.mask = TVIF_HANDLE | TVIF_IMAGE | TVIF_SELECTEDIMAGE;
                tvi.hItem = hti.hItem;
                TreeView_GetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
                tvi.iImage = tvi.iSelectedImage = tvi.iImage == 1 ? 2 : 1;
                TreeView_SetItem(((LPNMHDR) lParam)->hwndFrom, &tvi);
                SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
              }
          }
          break;
        case 0:
          switch (((LPNMHDR) lParam)->code) {
            case PSN_APPLY:
              {
                DWORD msgTimeout, avatarHeight;

                SRMMWriteSettingDword(SRMSGSET_POPFLAGS, MakeCheckBoxTreeFlags(GetDlgItem(hwndDlg, IDC_POPLIST)));
                StoreDBCheckState(hwndDlg, IDC_SHOWBUTTONLINE, SRMSGSET_SHOWBUTTONLINE);
                StoreDBCheckState(hwndDlg, IDC_SHOWINFOLINE, SRMSGSET_SHOWINFOLINE);
                StoreDBCheckState(hwndDlg, IDC_AUTOMIN, SRMSGSET_AUTOMIN);
                StoreDBCheckState(hwndDlg, IDC_AUTOCLOSE, SRMSGSET_AUTOCLOSE);
                StoreDBCheckState(hwndDlg, IDC_SAVEPERCONTACT, SRMSGSET_SAVEPERCONTACT);
                StoreDBCheckState(hwndDlg, IDC_CASCADE, SRMSGSET_CASCADE);
                StoreDBCheckState(hwndDlg, IDC_SENDONENTER, SRMSGSET_SENDONENTER);
                StoreDBCheckState(hwndDlg, IDC_SENDONDBLENTER, SRMSGSET_SENDONDBLENTER);
                StoreDBCheckState(hwndDlg, IDC_STATUSWIN, SRMSGSET_STATUSICON);

                StoreDBCheckState(hwndDlg, IDC_AVATARSUPPORT, SRMSGSET_AVATARENABLE);
                StoreDBCheckState(hwndDlg, IDC_LIMITAVATARH, SRMSGSET_LIMITAVHEIGHT);
                avatarHeight = GetDlgItemInt(hwndDlg, IDC_AVATARHEIGHT, NULL, TRUE);
                SRMMWriteSettingDword(SRMSGSET_AVHEIGHT, avatarHeight<=0?SRMSGDEFSET_AVHEIGHT:avatarHeight);

                StoreDBCheckState(hwndDlg, IDC_SHOWSENDBTN, SRMSGSET_SENDBUTTON);
                StoreDBCheckState(hwndDlg, IDC_CHARCOUNT, SRMSGSET_CHARCOUNT);
                StoreDBCheckState(hwndDlg, IDC_AUTOSAVEMSG, SRMSGSET_AUTOSAVEMSG);
                msgTimeout = GetDlgItemInt(hwndDlg, IDC_SECONDS, NULL, TRUE) >= SRMSGSET_MSGTIMEOUT_MIN / 1000 ? GetDlgItemInt(hwndDlg, IDC_SECONDS, NULL, TRUE) * 1000 : SRMSGDEFSET_MSGTIMEOUT;
                SRMMWriteSettingDword(SRMSGSET_MSGTIMEOUT, msgTimeout);
                ReloadGlobals();
                WindowList_Broadcast(g_dat->hMessageWindowList, DM_OPTIONSAPPLIED, 0, 0);
                return TRUE;
              }
          }
          break;
      }
      break;
    case WM_DESTROY:
      break;
  }
  return FALSE;
}

static INT_PTR CALLBACK DlgProcLogOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static HBRUSH hBkgColourBrush;

  switch (msg) {
    case WM_INITDIALOG:
      TranslateDialogDefault(hwndDlg);
      switch (SRMMGetSettingByte(SRMSGSET_LOADHISTORY, SRMSGDEFSET_LOADHISTORY)) {
        case LOADHISTORY_UNREAD:
          CheckDlgButton(hwndDlg, IDC_LOADUNREAD, BST_CHECKED);
          break;
        case LOADHISTORY_COUNT:
          CheckDlgButton(hwndDlg, IDC_LOADCOUNT, BST_CHECKED);
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTN), TRUE);
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTSPIN), TRUE);
          break;
        case LOADHISTORY_TIME:
          CheckDlgButton(hwndDlg, IDC_LOADTIME, BST_CHECKED);
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMEN), TRUE);
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMESPIN), TRUE);
          EnableWindow(GetDlgItem(hwndDlg, IDC_STMINSOLD), TRUE);
          break;
      }
      SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETRANGE, 0, MAKELONG(100, 0));
      SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_SETPOS, 0, SRMMGetSettingWord(SRMSGSET_LOADCOUNT, SRMSGDEFSET_LOADCOUNT));
      SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETRANGE, 0, MAKELONG(12 * 60, 0));
      SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_SETPOS, 0, SRMMGetSettingWord(SRMSGSET_LOADTIME, SRMSGDEFSET_LOADTIME));

      LoadDBCheckState(hwndDlg, IDC_SHOWLOGICONS, SRMSGSET_SHOWLOGICONS, SRMSGDEFSET_SHOWLOGICONS);
      CheckDlgButton(hwndDlg, IDC_SHOWNAMES, !SRMMGetSettingByte(SRMSGSET_HIDENAMES, SRMSGDEFSET_HIDENAMES));
      LoadDBCheckState(hwndDlg, IDC_SHOWTIMES, SRMSGSET_SHOWTIME, SRMSGDEFSET_SHOWTIME);
      EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSECS), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
      LoadDBCheckState(hwndDlg, IDC_SHOWSECS, SRMSGSET_SHOWSECS, SRMSGDEFSET_SHOWSECS);
      EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWDATES), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
      LoadDBCheckState(hwndDlg, IDC_SHOWDATES, SRMSGSET_SHOWDATE, SRMSGDEFSET_SHOWDATE);
      LoadDBCheckState(hwndDlg, IDC_SHOWURLS, SRMSGSET_SHOWURLS, SRMSGDEFSET_SHOWURLS);
      LoadDBCheckState(hwndDlg, IDC_SHOWFILES, SRMSGSET_SHOWFILES, SRMSGDEFSET_SHOWFILES);
      LoadDBCheckState(hwndDlg, IDC_SHOWCUSTOMEVENTS, SRMSGSET_SHOWCUSTOMEVENTS, SRMSGDEFSET_SHOWCUSTOMEVENTS);
      return TRUE;

    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDC_LOADUNREAD:
        case IDC_LOADCOUNT:
        case IDC_LOADTIME:
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTN), IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADCOUNTSPIN), IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT));
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMEN), IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
          EnableWindow(GetDlgItem(hwndDlg, IDC_LOADTIMESPIN), IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
          EnableWindow(GetDlgItem(hwndDlg, IDC_STMINSOLD), IsDlgButtonChecked(hwndDlg, IDC_LOADTIME));
          break;

        case IDC_SHOWTIMES:
          EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSECS), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
          EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWDATES), IsDlgButtonChecked(hwndDlg, IDC_SHOWTIMES));
          break;

        case IDC_LOADCOUNTN:
        case IDC_LOADTIMEN:
          if (HIWORD(wParam) != EN_CHANGE || (HWND) lParam != GetFocus())
            return TRUE;
          break;
      }
      SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
      break;
    case WM_NOTIFY:
      switch (((LPNMHDR) lParam)->idFrom) {
        case 0:
          switch (((LPNMHDR) lParam)->code) {
            case PSN_APPLY:
              if (IsDlgButtonChecked(hwndDlg, IDC_LOADCOUNT))
                SRMMWriteSettingByte(SRMSGSET_LOADHISTORY, LOADHISTORY_COUNT);
              else if (IsDlgButtonChecked(hwndDlg, IDC_LOADTIME))
                SRMMWriteSettingByte(SRMSGSET_LOADHISTORY, LOADHISTORY_TIME);
              else
                SRMMWriteSettingByte(SRMSGSET_LOADHISTORY, LOADHISTORY_UNREAD);
              SRMMWriteSettingWord(SRMSGSET_LOADCOUNT, (WORD)SendDlgItemMessage(hwndDlg, IDC_LOADCOUNTSPIN, UDM_GETPOS, 0, 0));
              SRMMWriteSettingWord(SRMSGSET_LOADTIME,  (WORD)SendDlgItemMessage(hwndDlg, IDC_LOADTIMESPIN, UDM_GETPOS, 0, 0));
              StoreDBCheckState(hwndDlg, IDC_SHOWLOGICONS, SRMSGSET_SHOWLOGICONS);
              SRMMWriteSettingByte(SRMSGSET_HIDENAMES, (BYTE)!IsDlgButtonChecked(hwndDlg, IDC_SHOWNAMES));
              StoreDBCheckState(hwndDlg, IDC_SHOWTIMES, SRMSGSET_SHOWTIME);
							StoreDBCheckState(hwndDlg, IDC_SHOWSECS, SRMSGSET_SHOWSECS);
              StoreDBCheckState(hwndDlg, IDC_SHOWDATES, SRMSGSET_SHOWDATE);
              StoreDBCheckState(hwndDlg, IDC_SHOWURLS, SRMSGSET_SHOWURLS);
              StoreDBCheckState(hwndDlg, IDC_SHOWFILES, SRMSGSET_SHOWFILES);
              StoreDBCheckState(hwndDlg, IDC_SHOWCUSTOMEVENTS, SRMSGSET_SHOWCUSTOMEVENTS);

              FreeMsgLogIcons();
              LoadMsgLogIcons();
              ReloadGlobals();
              WindowList_Broadcast(g_dat->hMessageWindowList, DM_OPTIONSAPPLIED, 0, 0);
              return TRUE;
          }
          break;
      }
      break;
    case WM_DESTROY:
      DeleteObject(hBkgColourBrush);
      break;
  }
  return FALSE;
}

static ResetCList(HWND hwndDlg)
{
  int i;

  if (CallService(MS_CLUI_GETCAPS, 0, 0) & CLUIF_DISABLEGROUPS && !DBGetContactSettingByte(NULL, "CList", "UseGroups", SETTING_USEGROUPS_DEFAULT))
    SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) FALSE, 0);
  else
    SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETUSEGROUPS, (WPARAM) TRUE, 0);
  SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETHIDEEMPTYGROUPS, 1, 0);
  SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETGREYOUTFLAGS, 0, 0);
  SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETLEFTMARGIN, 2, 0);
  SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKBITMAP, 0, (LPARAM) (HBITMAP) NULL);
  SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0);
  SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETINDENT, 10, 0);
  for (i = 0; i <= FONTID_MAX; i++)
    SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT));
}

static void RebuildList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown)
{
  HANDLE hContact, hItem;
  BYTE defType = SRMMGetSettingByte(SRMSGSET_TYPINGNEW, SRMSGDEFSET_TYPINGNEW);

  if (hItemNew && defType) {
    SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemNew, 1);
  }
  if (hItemUnknown && SRMMGetSettingByte(SRMSGSET_TYPINGUNKNOWN, SRMSGDEFSET_TYPINGUNKNOWN)) {
    SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItemUnknown, 1);
  }
  hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
  do {
    hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
    if (hItem && DBGetContactSettingByte(hContact, SRMSGMOD, SRMSGSET_TYPING, defType)) {
      SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_SETCHECKMARK, (WPARAM) hItem, 1);       
    }
  } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
}

static void SaveList(HWND hwndDlg, HANDLE hItemNew, HANDLE hItemUnknown)
{
  HANDLE hContact, hItem;

  if (hItemNew) {
    SRMMWriteSettingByte(SRMSGSET_TYPINGNEW, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemNew, 0) ? 1 : 0));
  }
  if (hItemUnknown) {
    SRMMWriteSettingByte(SRMSGSET_TYPINGUNKNOWN, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItemUnknown, 0) ? 1 : 0));
  }
  hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0);
  do {
    hItem = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_FINDCONTACT, (WPARAM) hContact, 0);
    if (hItem) {
      DBWriteContactSettingByte(hContact, SRMSGMOD, SRMSGSET_TYPING, (BYTE)(SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_GETCHECKMARK, (WPARAM) hItem, 0) ? 1 : 0));
    }
  } while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0));
}

static INT_PTR CALLBACK DlgProcTypeOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
  static HANDLE hItemNew, hItemUnknown;

  switch (msg) {
    case WM_INITDIALOG:
      TranslateDialogDefault(hwndDlg);
      {
        CLCINFOITEM cii = { 0 };
        cii.cbSize = sizeof(cii);
        cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX;
        cii.pszText = TranslateT("** New contacts **");
        hItemNew = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii);
        cii.pszText = TranslateT("** Unknown contacts **");
        hItemUnknown = (HANDLE) SendDlgItemMessage(hwndDlg, IDC_CLIST, CLM_ADDINFOITEM, 0, (LPARAM) & cii);
      }
      SetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CLIST), GWL_STYLE, GetWindowLongPtr(GetDlgItem(hwndDlg, IDC_CLIST), GWL_STYLE) | (CLS_SHOWHIDDEN) | (CLS_NOHIDEOFFLINE));
      ResetCList(hwndDlg);
      RebuildList(hwndDlg, hItemNew, hItemUnknown);
      LoadDBCheckState(hwndDlg, IDC_SHOWNOTIFY, SRMSGSET_SHOWTYPING, SRMSGDEFSET_SHOWTYPING);
      LoadDBCheckState(hwndDlg, IDC_TYPEWIN, SRMSGSET_SHOWTYPINGWIN, SRMSGDEFSET_SHOWTYPINGWIN);
      LoadDBCheckState(hwndDlg, IDC_TYPETRAY, SRMSGSET_SHOWTYPINGNOWIN, SRMSGDEFSET_SHOWTYPINGNOWIN);
      LoadDBCheckState(hwndDlg, IDC_NOTIFYTRAY, SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST);
      CheckDlgButton(hwndDlg, IDC_NOTIFYBALLOON, !SRMMGetSettingByte(SRMSGSET_SHOWTYPINGCLIST, SRMSGDEFSET_SHOWTYPINGCLIST));
      EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEWIN), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
      EnableWindow(GetDlgItem(hwndDlg, IDC_TYPETRAY), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
      EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY));
      EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY));
      if (!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
        EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), FALSE);
        CheckDlgButton(hwndDlg, IDC_NOTIFYTRAY, BST_CHECKED);
        SetWindowText(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), TranslateT("Show balloon popup (unsupported system)"));
      }
      break;
    case WM_COMMAND:
      switch (LOWORD(wParam)) {
        case IDC_TYPETRAY:
					if (IsDlgButtonChecked(hwndDlg, IDC_TYPETRAY)) {
						if (!ServiceExists(MS_CLIST_SYSTRAY_NOTIFY)) {
							EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), TRUE);
						}
						else {
							EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), TRUE);
							EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), TRUE);
						}
					}
					else {
						EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), FALSE);
						EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), FALSE);
					}
					SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
					break;
        case IDC_SHOWNOTIFY:
          EnableWindow(GetDlgItem(hwndDlg, IDC_TYPEWIN), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
          EnableWindow(GetDlgItem(hwndDlg, IDC_TYPETRAY), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
          EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYTRAY), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY));
					EnableWindow(GetDlgItem(hwndDlg, IDC_NOTIFYBALLOON), IsDlgButtonChecked(hwndDlg, IDC_SHOWNOTIFY)
            && ServiceExists(MS_CLIST_SYSTRAY_NOTIFY));
          //fall-thru
        case IDC_TYPEWIN:
				case IDC_NOTIFYTRAY:
				case IDC_NOTIFYBALLOON:
					SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
          break;
      }
      break;
    case WM_NOTIFY:
      switch (((NMHDR *) lParam)->idFrom) {
        case IDC_CLIST:
          switch (((NMHDR *) lParam)->code) {
            case CLN_OPTIONSCHANGED:
              ResetCList(hwndDlg);
              break;
            case CLN_CHECKCHANGED:
              SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
              break;
          }
          break;
        case 0:
          switch (((LPNMHDR) lParam)->code) {
            case PSN_APPLY:
              {
                SaveList(hwndDlg, hItemNew, hItemUnknown);
                StoreDBCheckState(hwndDlg, IDC_SHOWNOTIFY, SRMSGSET_SHOWTYPING);
                StoreDBCheckState(hwndDlg, IDC_TYPEWIN,    SRMSGSET_SHOWTYPINGWIN);
                StoreDBCheckState(hwndDlg, IDC_TYPETRAY,   SRMSGSET_SHOWTYPINGNOWIN);
                StoreDBCheckState(hwndDlg, IDC_NOTIFYTRAY, SRMSGSET_SHOWTYPINGCLIST);
                ReloadGlobals();
                WindowList_Broadcast(g_dat->hMessageWindowList, DM_OPTIONSAPPLIED, 0, 0);
              }
          }
          break;
      }
      break;
  }
  return FALSE;
}

static int OptInitialise(WPARAM wParam, LPARAM lParam)
{
  OPTIONSDIALOGPAGE odp = { 0 };

  odp.cbSize = sizeof(odp);
  odp.position = 910000000;
  odp.hInstance = g_hInst;
  odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGDLG);
  odp.pszTab = LPGEN("Messaging");
  odp.pszTitle = LPGEN("Messaging");
  odp.pszGroup = LPGEN("Events");
  odp.pfnDlgProc = DlgProcOptions;
  odp.flags = ODPF_BOLDGROUPS;
  CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);

  odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGLOG);
  odp.pszTab = LPGEN("Messaging Log");
  odp.pfnDlgProc = DlgProcLogOptions;
  odp.nIDBottomSimpleControl = IDC_STMSGLOGGROUP;
  CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);

  odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MSGTYPE);
  odp.pszTab = LPGEN("Typing Notify");
  odp.pfnDlgProc = DlgProcTypeOptions;
  odp.nIDBottomSimpleControl = 0;
  CallService(MS_OPT_ADDPAGE, wParam, (LPARAM) & odp);
  return 0;
}

int InitOptions(void)
{
  HookEvent(ME_OPT_INITIALISE, OptInitialise);
  return 0;
}
